﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TrackerRealm.Jazz.Client;
using PostSharp.Extensibility;
using TrackerRealm.Jazz.Client.Custom;

namespace JazzClientInternalTest
{
    /// <summary>
    /// Demonstrates how use the 'GrantProperty' attribute in the 'object owner' use case.
    /// <para>Owner is 'jProfile'</para>
    /// <para>In this use case an Owner is assigned to a Jazz object and only the owner
    /// may edit the request data.</para>
    /// </summary>
    [TestClass]
    public class GrantPropertyTest
    {
        /// <summary>
        /// 
        /// </summary>
        [TestMethod]
        public void GrantProperty_Success_Verboise()
        {
            NexusConfig config = new NexusConfig()
            {
                LoginProfile = jUser.Create("MyUser"),
                RoleCheckCollection = new string[]{"Manager"},
                Verbose = VerboseType.All,
            };
            using (ClientNexus nexus = ClientNexus.Create(config))
            {
                PersonnelRequest request = new PersonnelRequest(nexus);
                request.Request = "May I have the day off on Friday?";
                Assert.AreEqual("Approval", request.CurrentState.Name);
                request.Edit();
                Assert.AreEqual("Start", request.CurrentState.Name);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [TestMethod]
        public void GrantProperty_Failure_Verboise()
        {
            NexusConfig config = new NexusConfig()
            {
                LoginProfile = jUser.Create("MyUser"),
                RoleCheckCollection = new string[] { "Manager" },
                Verbose = VerboseType.All,
            };
            using (ClientNexus nexus = ClientNexus.Create(config))
            {
                PersonnelRequest request = new PersonnelRequest(nexus);
                request.Request = "May I have the day off on Friday?";
                Assert.AreEqual("Approval", request.CurrentState.Name);
                nexus.ChangeLoginProfile(jUser.Create("Joe"));
                bool isExceptionOccurred = false;
                try
                {
                    request.Edit();  // Joe is not the owner - only the owner can edit.
                }
                catch (Exception ex)
                {
                    isExceptionOccurred = true;
                    Assert.IsTrue(ex is AccessViolationException);
                }
                Assert.IsTrue(isExceptionOccurred);
            }
        }
        #region PersonnelRequest Class - Used in all GrantProperty tests
        /// <summary>
        /// This is a small class that demonstrates the use of states in
        /// a personel request.
        /// The class is very simple only allowing a request to made and
        /// then approved.
        /// **************************
        /// Use Case: - A user ('Owner') creates a request object that must be approved
        /// by another user with the role of 'Manager'.  As long as the
        /// the request is not approved the 'Owner' can edit the request.
        /// Once the request is approved no changes can be made.
        /// **************************
        /// Use Case Enhancements: Adding the ability to delete the object
        /// by the 'owner' and 'reject' the request by the 'manager' are obvious
        /// enhancements.
        /// </summary>
        [Jazz]
        public class PersonnelRequest : jObject
        {
            #region Constructor
            /// <summary>
            /// Constructor
            /// </summary>
            public PersonnelRequest(ClientNexus nexus)
            :base(nexus)
            {
                this.requestData = "";
                this.IsApproved = false;
                if(this.IsEmpty)
                   this.Owner = (jProfile)nexus.LoginProfile.Class.EmptyInstance;
                else
                    this.Owner = nexus.LoginProfile;
            }
            #endregion
            #region Owner
            /// <summary>
            /// Returns the user that created this 'PersonnelRequest' instance.
            /// </summary>
            public jProfile Owner
            {
                get;
                private set;
            }
            #endregion
            #region Request
            private string requestData;
            /// <summary>
            /// Make a request by setting the data.
            /// Only the Jazz Object owner
            /// is allowed to set the data.
            /// </summary>
            [UI]
            public string Request
            {
                get { return this.requestData; }
                [GrantStates("Start")]
                [GrantProperty("Owner")]  // only allow the owner to make changes.
                set
                {
                    this.requestData = value;
                    // prevent the data from being changed.
                    this.EnterState("Approval");
                }
            }
            #endregion
            #region IsApproved
            /// <summary>
            /// Returns true when the Request has been approved.
            /// </summary>
            [UI]
            public bool IsApproved
            {
                get;
                private set;
            }
            #endregion
            #region Approve/Edit
            /// <summary>
            /// The approve method is only allowed to be executed when this instance is the 'Approval State'.
            /// </summary>
            [UI]
            [GrantStates("Approval")]
            [GrantRoles("Manager")]
            public void Approve()
            {
                this.IsApproved = true;
                // prevent the workflow from being approved again.
                this.EnterState("Completed");
            }
            /// <summary>
            /// Return to Start state to edit the request.  Only the Jazz Object owner
            /// is allowed to perform this action.
            /// </summary>
            [GrantStates("Approval")]
            [GrantProperty("Owner")]
            public void Edit()
            {
                this.EnterState("Start");
            }
            #endregion
            #region States
            //
            // A ProfilelRequest instance has its 'CurrentState' set to one
            // of the following states.
            //
            #region Start
            [StartState]
            void Start()
            {
                // this will be written to the console when the state is entered.
                Console.WriteLine(this.ToString() + ".StartMsg:\t\t***** Getting Started ******");
            }
            #endregion
            #region Completed
            [State]
            void Completed()
            {
                // this will be written to the console when the state is entered.
                Console.WriteLine(this.ToString() + ".CompletedMsg:\t\t***** Completed ******");
            }
            #endregion
            #region Approval
            [FinalState]
            void Approval()
            {
            }
            #endregion
            #endregion
        }
        #endregion
    }
}
